import cv2 as cv
import numpy as np
import os
import logging as log


this_dir = os.path.dirname(os.path.realpath(__file__))
data_dir = os.path.join(this_dir, '../../data')
fingers_dir = os.path.join(data_dir, 'Fingers/test_20200714/test')

logger = log.getLogger(__name__)
log.basicConfig(level=log.DEBUG,
                format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')


def calc_octave_counts(image):
    "计算金字塔的组数"
    logger.debug('calc_octave_counts...')
    counts = np.round(np.log2(min(image.shape)) - 2)
    return int(counts)


def calc_gaussian_kernels(sigma, num_intervals):
    """计算高斯核的模糊系数
    ***[sigma]：指的是初始的模糊系数，推荐使用1.6
    ***[num_intervals]：指的是极值检测需要的层数[3~5]
    """
    logger.debug('calc_gaussian_kernels...')
    num_images_per_octave = num_intervals + 3
    k = 2**(1. / num_intervals)
    gaussian_kernels = np.zeros(num_images_per_octave)
    # scale of gaussian blur necessary to go from one blur scale to the next within an octave
    gaussian_kernels[0] = sigma

    for image_index in range(1, num_images_per_octave):
        sigma_previous = (k**(image_index - 1)) * sigma
        sigma_total = k * sigma_previous
        gaussian_kernels[image_index] = np.sqrt(sigma_total**2
                                                - sigma_previous**2)
    return gaussian_kernels


def generate_gaussian_pyr(image, num_octave, gaussian_kernels):
    """产生高斯金字塔
    ***[image]:             原始灰度图像
    ***[num_octave]:        组数
    ***[gaussian_kernels]:  高斯的模糊系数
    """
    gaussian_images = []

    for octave_index in range(num_octave):
        gaussian_images_in_octave = []
        gaussian_images_in_octave.append(
            image)  # first image in octave already has the correct blur
        for gaussian_kernel in gaussian_kernels[1:]:
            image = cv.GaussianBlur(image, (0, 0),
                                    sigmaX=gaussian_kernel,
                                    sigmaY=gaussian_kernel)
            gaussian_images_in_octave.append(image)
        gaussian_images.append(gaussian_images_in_octave)
        octave_base = gaussian_images_in_octave[-3]
        image = cv.resize(
            octave_base,
            (int(octave_base.shape[1] / 2), int(octave_base.shape[0] / 2)),
            interpolation=cv.INTER_NEAREST)
    return np.array(gaussian_images)


def generate_dog_images(gaussian_images):
    '''generate the difference of gaussian images
    ***[gaussian_images]    生成的高斯模糊图像
    '''
    logger.debug('Generating Difference-of-Gaussian images...')
    dog_images = []

    for gaussian_images_in_octave in gaussian_images:
        dog_images_in_octave = []
        for first_image, second_image in zip(gaussian_images_in_octave,
                                             gaussian_images_in_octave[1:]):
            dog_images_in_octave.append(np.subtract(second_image, first_image))
        dog_images.append(dog_images_in_octave)
    return np.array(dog_images)


if __name__ == "__main__":
    finger_file = os.path.join(fingers_dir, '0002_0_1.png')
    image = cv.imread(finger_file, cv.IMREAD_GRAYSCALE)
    counts = calc_octave_counts(image)
    gaussian_kernels = calc_gaussian_kernels(sigma=1.6, num_intervals=3)
    gaussian_images = generate_gaussian_pyr(image, counts, gaussian_kernels)
    dog_images = generate_dog_images(gaussian_images)
    import matplotlib.pyplot as plt

    r, c = gaussian_images.shape
    for i in range(r):
        for j in range(c):
            plt.subplot(r,
                        c,
                        i * c + j + 1)
            plt.imshow(gaussian_images[i][j], cmap='gray')
    plt.show()
